
//Copyright 1997-2009 Syrinx Development, Inc.
//This file is part of the Syrinx Web Application Framework (SWAF).
// == BEGIN LICENSE ==
//
// Licensed under the terms of any of the following licenses at your
// choice:
//
//  - GNU General Public License Version 3 or later (the "GPL")
//    http://www.gnu.org/licenses/gpl.html
//
//  - GNU Lesser General Public License Version 3 or later (the "LGPL")
//    http://www.gnu.org/licenses/lgpl.html
//
//  - Mozilla Public License Version 1.1 or later (the "MPL")
//    http://www.mozilla.org/MPL/MPL-1.1.html
//
// == END LICENSE ==
using System;
using System.Diagnostics;
using System.IO;
using System.Net;
using System.Text;

namespace Swaf.Crypto
{
	/// <summary>
	/// Summary description for FileCryptoWebRequest.
	/// </summary>
	public class FileCryptoWebRequest : WebRequest
	{
		private const string BEGIN_IDENTIFIER = "KINFO-->";
		private const string END_IDENTIFIER = "<--KINFO";
		private Uri m_uri;

		public FileCryptoWebRequest(Uri uri)
		{
			m_uri = uri;
		}

		public override WebResponse GetResponse()
		{
			return new CryptoFileResponse(m_uri);
		}

		class CryptoFileResponse : WebResponse
		{
			private Uri m_uri = null;
			private Stream m_readStream = null;
			private Stream m_cryptoStream = null;

			public CryptoFileResponse(Uri uri)
			{
				m_uri = uri;
			}

			public override Stream GetResponseStream()
			{
				m_readStream = null;
				string localPath = m_uri.LocalPath.Replace(@"/",@"\").ToLower();
				string host = m_uri.Host.ToLower();
				if ( (! host.Equals(string.Empty)) && (! localPath.StartsWith(@"\\" + host)) )
				{
					if (localPath.StartsWith(host))
					{
						localPath = @"\\" + localPath;
					}
					else
					{
						localPath=@"\\" + host + localPath;
					}
				}
				FileInfo f = new FileInfo(localPath);
				if(f.Exists)
				{
					m_readStream = f.OpenRead();
					if(String.Compare(f.Extension, ".enc", true) == 0)
					{
						string keyName = string.Empty;

						// Extract out the BEGIN_IDENTIFIER if it exists
						byte [] hdrPrefix = Encoding.UTF8.GetBytes(BEGIN_IDENTIFIER);
						int currPos = m_readStream.Read(hdrPrefix, 0, hdrPrefix.Length);

						// Convert the initial look up to string to see if it has a header
						string beginId = Encoding.UTF8.GetString(hdrPrefix);
						if (string.Compare(beginId, BEGIN_IDENTIFIER) == 0)
						{
							// This has a header so we need to find the key
							string header = beginId;
							while (true)
							{
								// Read 100 byte blocks
								byte [] block = new byte[100];
								currPos += m_readStream.Read(block, 0, 100);

								// Convert block to a string representation
								string blockString = Encoding.UTF8.GetString(block);

								// Add block to header data
								header += blockString;

								// See if the END_IDENTIFIER has been found
								int endIdIndex = header.IndexOf(END_IDENTIFIER);
								if (endIdIndex != -1)
								{
									// Found the end of the header

									// Extract the Key name
									keyName = header.Substring(beginId.Length, endIdIndex - beginId.Length);

									// Reset the input stream to the correct location
									currPos = endIdIndex + END_IDENTIFIER.Length;

									// Set the stream index to just after the END_IDENTIFIER
									m_readStream.Seek(currPos, SeekOrigin.Begin);

									// break out of the loop, we got what we needed.
									break;
								}
							}
						}
						else
						{
							// No header containing keyname in the beginning of stream, seek back to the beginning
							m_readStream.Seek(0, SeekOrigin.Begin);
						}

						ICryptoManager cryptoManager = (ICryptoManager)Application.currentApp.appData["sysObjs-Crypto"];
						m_cryptoStream = cryptoManager.createCryptoStream(keyName, m_readStream);
					}

				}

				return m_cryptoStream==null?m_readStream:m_cryptoStream;
			}

			public override void Close()
			{
				base.Close ();
				if(m_cryptoStream != null)
					m_cryptoStream.Close();
				if(m_readStream != null)
					m_readStream.Close();
			}


			public override long ContentLength 
			{
				get 
				{
					FileInfo f = new FileInfo(m_uri.LocalPath);
					return (f.Exists) ? f.Length : 0;
				} 
			}
			public override string ContentType {get {return "text/text";} }
			public override Uri ResponseUri {get {return m_uri;} }
		}

	}
}
